package com.coderg.gmall.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.coderg.gmall.cart.feign.CartFeign;
import com.coderg.gmall.common.result.Result;
import com.coderg.gmall.model.cart.CartInfo;
import com.coderg.gmall.model.enums.OrderStatus;
import com.coderg.gmall.model.enums.ProcessStatus;
import com.coderg.gmall.model.order.OrderDetail;
import com.coderg.gmall.model.order.OrderInfo;
import com.coderg.gmall.model.user.UserAddress;
import com.coderg.gmall.order.config.RabbitConfig;
import com.coderg.gmall.order.mapper.OrderDetailMapper;
import com.coderg.gmall.order.mapper.OrderInfoMapper;
import com.coderg.gmall.order.service.OrderInfoService;
import com.coderg.gmall.product.ItemProductFeign;
import com.coderg.gmall.user.UserAddressFeign;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author CoderG
 * @Date 2025/6/10 18:02
 **/
@Service
@Slf4j
public class OrderInfoSerciveImpl implements OrderInfoService {
    String username = "atguigu";
    @Autowired
    OrderInfoMapper orderInfoMapper;
    @Autowired
    UserAddressFeign userAddressFeign;
    @Autowired
    CartFeign cartFeign;
    @Autowired
    ItemProductFeign itemFeign;
    @Autowired
    OrderDetailMapper orderDetailMapper;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RedissonClient redissonClient;
    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 生成订单  要使用分布式事务seata
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrder() {
        /**
         * 获取用户名
         * 查询用户信息 手机号 查询收货地址
         * 查询购物车
         * 查询最新价格
         * 计算总价
         * 查询库存
         * 生成订单
         *  接口的幂等性   回退多次下同一单 多端下单  分布式锁   为什么加锁 锁是什么 在哪里加
         *
         */
        //key order:username:uuid
        String orderFlag = (String) redisTemplate.opsForValue().get("order1:" + username);
        if (orderFlag != null) {
            return;
        }
        //查用户地址以及其他信息
        List<UserAddress> userAddressList = userAddressFeign.findUserAddressListByUserId();

        if (userAddressList == null || userAddressList.isEmpty()) {
            return;
        }
        //获取默认地址
        List<UserAddress> addresses = userAddressList.stream()
                .filter(userAddress -> "1".equals(userAddress.getIsDefault()))
                .collect(Collectors.toList());
        // List<CartInfo> carts
        //获取购物结算页面
        Result result = cartFeign.cartConfirm();
        Map data = (Map) result.getData();
        //因为购物车可能为空
        if (data == null) {
            return;
        }
        List<Object> list = (List) data.get("carts");
        List<CartInfo> newCarts = list.stream().map(o -> {
            //序列化
            String s = JSONObject.toJSONString(o);
            //反序列化
            return JSONObject.parseObject(s, CartInfo.class);
        }).collect(Collectors.toList());
        //获取总价
        Integer price = (Integer) data.get("totalPrice");
        BigDecimal totalPrice = new BigDecimal(price.toString());

        //生成订单
        RLock lock = redissonClient.getLock("order:" + username);
        try {
            //waitTime等待时间 0是尝试一次不等待  1是阻塞1秒   leaseTime（过期时间）   时间单位
            if (lock.tryLock(0, 10, TimeUnit.SECONDS)) {
                try {
                    //保存订单
                    OrderInfo orderInfo = saveOrderInfo(addresses, totalPrice);
                    //保存订单详情
                    saveOrderDetail(newCarts, orderInfo);
                    redisTemplate.opsForValue().set("order1:" + username, "qwer", 10, TimeUnit.SECONDS);

                    //清空购物车
                    if (!cartFeign.clearCarts()) {
                        throw new RuntimeException("清空购物车失败");
                    }

                    //得到 map<skuId,num>
                    Map<Long, Integer> stockMap = newCarts.stream()
                            .collect(Collectors.toMap(CartInfo::getSkuId, CartInfo::getSkuNum));
                    //扣库存 失败就回滚
                    if (!itemFeign.decreaseStockpile(stockMap)) {
                        throw new RuntimeException("扣库存失败");
                    }
                    //加积分等
                    //超时订单处理  超过三十分钟未支付，修改订单状态为超时取消
                    //orderId
                    Message message = new Message((orderInfo.getId() + "")
                            .getBytes(), new MessageProperties());
                    rabbitTemplate.convertAndSend(
                            RabbitConfig.BUSINESS_EXCHANGE,
                            RabbitConfig.BUSINESS_ROUTING_KEY,
                            message);
                } catch (Exception e) {
                    log.error("生成订单异常: " + e.getMessage());
                    throw new RuntimeException(e.getMessage(), e);
                } finally {
                    lock.unlock();
                }
            } else {
                throw new RuntimeException("重复下单");
            }
        } catch (InterruptedException e) {
            log.error("加锁异常原因: " + e.getMessage());
            throw new RuntimeException("加锁异常原因: " + e.getMessage());
        }

    }

    /**
     * 取消订单   主动取消 超时取消  幂等性
     *
     * @param id
     * @param flag
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Long id, String flag) {
        //根据订单号取消订单
        //获取用户名 username
        if (id == null) {
            return;
        }
        //并发取消 重复取消
        RLock lock = redissonClient.getLock("order:" + id);
        try {
            if (lock.tryLock(0, 10, TimeUnit.SECONDS)) {
                try {
                    //公共的查询条件
                    // 必须是未支付状态  有状态鸡一定注意判断状态
                    LambdaQueryWrapper<OrderInfo> wrapper =
                            new LambdaQueryWrapper<OrderInfo>()
                                    .eq(OrderInfo::getId, id)
                                    .eq(OrderInfo::getOrderStatus, OrderStatus.UNPAID.getComment());
                    //修改订单状态   主动取消
                    if (username == null) {
                        //超时取消

                    } else {
                        //主动取消
                        wrapper.eq(OrderInfo::getUserId, username);
                    }

                    OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
                    if (orderInfo == null || orderInfo.getId() == null) {
                        return;
                    }
                    //修改订单状态
                    orderInfo.setOrderStatus(flag);
                    orderInfo.setProcessStatus(flag);
                    int update = orderInfoMapper.updateById(orderInfo);
                    if (update <= 0) {
                        throw new RuntimeException("取消订单失败");
                    }
                    //查询订单详情获取 map<string ,long>
                    List<OrderDetail> orderDetails = orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>()
                            .eq(OrderDetail::getOrderId, id));
                    Map<String, String> stockMap = orderDetails.stream().collect(Collectors.toMap(
                            orderDetail -> orderDetail.getSkuId() + "",
                            orderDetail1 -> orderDetail1.getSkuNum() + ""));

                    //回退库存
                    boolean b = itemFeign.rollbackStock(stockMap);
                    if (!b) {
                        throw new RuntimeException("回退库存失败");
                    }
                } catch (RuntimeException e) {
                    log.error("加锁正常但是业务逻辑错误：" + e.getMessage());
                    throw e;
                } finally {
                    //必须释放锁
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            log.error("加锁异常原因是: " + e.getMessage());
            throw new RuntimeException("加锁异常", e);
        }

    }

    private void saveOrderDetail(List<CartInfo> newCarts, OrderInfo orderInfo) {
        newCarts.forEach(cartInfo -> {
                    OrderDetail orderDetail = new OrderDetail();
                    orderDetail.setOrderId(orderInfo.getId());
                    orderDetail.setSkuId(cartInfo.getSkuId());
                    orderDetail.setOrderPrice(cartInfo.getSkuPrice());
                    orderDetail.setImgUrl(cartInfo.getImgUrl());
                    orderDetail.setSkuName(cartInfo.getSkuName());
                    orderDetail.setSkuNum(cartInfo.getSkuNum());
                    int insert = orderDetailMapper.insert(orderDetail);
                    if (insert <= 0) {
                        new RuntimeException("保存订单详情失败");
                    }
                }
        );
    }

    /**
     * 生成订单
     *
     * @param addresses
     * @param totalPrice
     * @return
     */
    private OrderInfo saveOrderInfo(List<UserAddress> addresses, BigDecimal totalPrice) {
        //构造订单
        OrderInfo orderInfo = new OrderInfo();
        //计算总价
        orderInfo.setTotalAmount(totalPrice);
        //收货人
        orderInfo.setConsignee(addresses.get(0).getConsignee());
        //号码
        orderInfo.setConsigneeTel(addresses.get(0).getPhoneNum());
        //userId
        orderInfo.setUserId(addresses.get(0).getUserId());
        //地址
        orderInfo.setDeliveryAddress(addresses.get(0).getUserAddress());
        //生成订单交易编号
        String outTradeNo = "atguigu" + UUID.randomUUID().toString();
        orderInfo.setOutTradeNo(outTradeNo);
        //生成订单描述
        orderInfo.setTradeBody("尚硅谷商城交易订单");
        //订单备注
        orderInfo.setOrderComment("无");
        //生成创建时间
        orderInfo.setCreateTime(new Date());
        //生成过期时间:半小时有效
        orderInfo.setExpireTime(new Date(System.currentTimeMillis() + 1800000));
        //设置进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.getComment());
        //设置订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.getComment());
        //保存图片url

        //保存订单数据
        int insert = orderInfoMapper.insert(orderInfo);
        if (insert <= 0) {
            throw new RuntimeException("生成订单失败");
        }
        return orderInfo;
    }
}
